home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 3 / CD ACTUAL 3.iso / linux / system / bsvc-1.000 / bsvc-1 / bsvc-1.0.4 / src / Sim68000 / devices / M68681.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-26  |  23.0 KB  |  896 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // $Id: M68681.cxx,v 1.3 1995/06/29 23:10:21 bmott Exp $
  3. ///////////////////////////////////////////////////////////////////////////////
  4. // M68681.hxx 
  5. //
  6. // The Motorola 68681 DUART
  7. //
  8. // Sim68000 "Motorola 68000 Simulator"
  9. // Copyright (c) 1993
  10. // By: Bradford W. Mott
  11. // Novermber 24,1993
  12. //
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // $Log: M68681.cxx,v $
  15. // Revision 1.3  1995/06/29  23:10:21  bmott
  16. // Fixed interrupt level argument parsing error
  17. //
  18. // Revision 1.2  1994/08/22  07:36:27  bmott
  19. // Changed the device argument parsing and the forking/execution of
  20. // port commands
  21. //
  22. // Revision 1.1  1994/02/18  20:12:08  bmott
  23. // Initial revision
  24. //
  25. ///////////////////////////////////////////////////////////////////////////////
  26.  
  27. #include <sys/types.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <signal.h>
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33.  
  34. #include "String.h"
  35. #include "Regex.h"
  36.  
  37. #include "Tools.hxx"
  38. #include "BasicCPU.hxx"
  39. #include "M68681.hxx"
  40.  
  41. // Callback types
  42. #define READ_A_CALLBACK   1
  43. #define WRITE_A_CALLBACK  2
  44. #define READ_B_CALLBACK   3
  45. #define WRITE_B_CALLBACK  4
  46.  
  47. // The duration of the default read events
  48. #define DEFAULT_READ_CALLBACK_DURATION  50000
  49.  
  50. // Channel/port states 
  51. #define ACTIVE   1
  52. #define INACTIVE 0
  53.  
  54. // Bit fields in status registers
  55. #define RxRDY    1
  56. #define FFULL    2
  57. #define TxRDY    4
  58. #define TxEMT    8
  59.  
  60.  
  61. ///////////////////////////////////////////////////////////////////////////////
  62. // Baudrate table (contains event duration times in micro-seconds)
  63. ///////////////////////////////////////////////////////////////////////////////
  64. long M68681::baudrate_table[32] = {
  65.     160000,    // 50     baudrate (i.e. (8*1000000)/50) uS)
  66.     72727,     // 110
  67.     59479,     // 134.5
  68.     40000,     // 200
  69.     26666,     // 300
  70.     13333,     // 600
  71.     6666,      // 1200
  72.     7619,      // 1050
  73.     3333,      // 2400
  74.     1666,      // 4800
  75.     1111,      // 7200
  76.     833,       // 9600
  77.     208,       // 38400
  78.     1666,      // 4800   (Should be timer but that's not implemented)
  79.     1666,      // 4800   (Should be IP4-16X but that's not implemented)
  80.     1666,      // 4800   (Should be IP4-1X but that's not implemented)
  81.     106666,    // 75
  82.     72727,     // 110
  83.     59479,     // 134.5
  84.     53333,     // 150
  85.     26666,     // 300
  86.     13333,     // 600
  87.     6666,      // 1200
  88.     4000,      // 2000
  89.     3333,      // 2400
  90.     1666,      // 4800
  91.     4444,      // 1800
  92.     833,       // 9600
  93.     416,       // 19200
  94.     1666,      // 4800   (Should be timer but that's not implemented)
  95.     1666,      // 4800   (Should be IP4-16X but that's not implemented)
  96.     1666       // 4800   (Should be IP4-1X but that's not implemented)
  97.   };
  98.  
  99. ///////////////////////////////////////////////////////////////////////////////
  100. // The Constructor
  101. ///////////////////////////////////////////////////////////////////////////////
  102. M68681::M68681(String args, BasicCPU* c)
  103.   : BasicDevice("M68681", args, c)
  104. {
  105.   Regex format("^BaseAddress=[0-9a-fA-F]+ OffsetToFirstRegister=[0-8] "
  106.            "OffsetBetweenRegisters=[1-8] InterruptLevel=[1-7] "
  107.            "PortACommand=.* PortAStandardInputOutputFlag=.* "
  108.            "PortBCommand=.* PortBStandardInputOutputFlag=.*$");
  109.  
  110.   // Make sure the argument string is in the correct format
  111.   if(args.contains(format))
  112.   {
  113.     String base_arg, offset_to_first_arg, offset_between_arg;
  114.     String interrupt_level_arg, port_a_command, port_a_std;
  115.     String port_b_command, port_b_std;
  116.     String remaining;
  117.  
  118.     // Parse through the argument list
  119.     remaining=args.after("BaseAddress=");
  120.     base_arg=remaining.before(" OffsetToFirstRegister=");
  121.     remaining=remaining.after(" OffsetToFirstRegister=");
  122.     offset_to_first_arg=remaining.before(" OffsetBetweenRegisters=");
  123.     remaining=remaining.after(" OffsetBetweenRegisters=");
  124.     offset_between_arg=remaining.before(" InterruptLevel=");
  125.     remaining=remaining.after(" InterruptLevel=");
  126.     interrupt_level_arg=remaining.before(" PortACommand=");
  127.     remaining=remaining.after(" PortACommand=");
  128.     port_a_command=remaining.before(" PortAStandardInputOutputFlag=");
  129.     remaining=remaining.after(" PortAStandardInputOutputFlag=");
  130.     port_a_std=remaining.before(" PortBCommand=");
  131.     remaining=remaining.after(" PortBCommand=");
  132.     port_b_command=remaining.before(" PortBStandardInputOutputFlag=");
  133.     port_b_std=remaining.after(" PortBStandardInputOutputFlag=");
  134.  
  135.     base_address=StringToInt(base_arg)*c->Granularity();
  136.     offset_to_first_register=StringToInt(offset_to_first_arg)*c->Granularity();
  137.     offset_between_registers=StringToInt(offset_between_arg)*c->Granularity();
  138.     interrupt_level=StringToInt(interrupt_level_arg);
  139.  
  140.     int port_a_std_flag;
  141.     int port_b_std_flag;
  142.  
  143.     if(port_a_std == "TRUE")
  144.       port_a_std_flag=1;
  145.     else
  146.       port_a_std_flag=0;
  147.  
  148.     if(port_b_std == "TRUE")
  149.       port_b_std_flag=1;
  150.     else
  151.       port_b_std_flag=0;
  152.  
  153.     // Default Invalid values for everything
  154.     coma_pid=coma_read_id=coma_write_id=-1;
  155.     comb_pid=comb_read_id=comb_write_id=-1;
  156.  
  157.     // Startup the process for port a
  158.     if(port_a_command!="")
  159.     {
  160.       if(!StartPortCommand(port_a_command, port_a_std_flag,
  161.               coma_read_id, coma_write_id, coma_pid))
  162.       {
  163.         SetErrorMessage("Problem starting port a's process!");
  164.         return;
  165.       }
  166.     }
  167.  
  168.     // Startup the process for port b
  169.     if(port_b_command!="")
  170.     {
  171.       if(!StartPortCommand(port_b_command, port_b_std_flag,
  172.               comb_read_id, comb_write_id, comb_pid))
  173.       {
  174.         SetErrorMessage("Problem starting port b's process!");
  175.         return;
  176.       } 
  177.     }
  178.  
  179.     // Reset the DUART to its startup state
  180.     Reset();
  181.  
  182.     if(coma_read_id != -1)
  183.     {
  184.       // Schedule an event to start checking the A pipe
  185.       cpu->events.Add(this, READ_A_CALLBACK,
  186.                (void*)0, DEFAULT_READ_CALLBACK_DURATION);
  187.     }
  188.  
  189.     if(comb_read_id != -1)
  190.     {
  191.       // Schedule an event to start checking the B pipe
  192.       cpu->events.Add(this, READ_B_CALLBACK,
  193.            (void*)0, DEFAULT_READ_CALLBACK_DURATION);
  194.     }
  195.   }
  196.   else
  197.   {
  198.     SetErrorMessage("Invalid initialization arguments!");
  199.   }
  200. }
  201.  
  202. ///////////////////////////////////////////////////////////////////////////////
  203. // Startup a process 
  204. ///////////////////////////////////////////////////////////////////////////////
  205. int M68681::StartPortCommand(String command, int std_flag,
  206.                              int &read_pipe_id, int &write_pipe_id, pid_t &pid)
  207. {
  208.   int t,read_pipe_ids[2],write_pipe_ids[2];
  209.  
  210.   // Create the write pipe 
  211.   if(pipe(write_pipe_ids))
  212.     return(0);
  213.  
  214.   // Create the read pipe 
  215.   if(pipe(read_pipe_ids))
  216.     return(0);
  217.  
  218.   // Set the NONBLOCK flag for the reading pipe
  219.   if(fcntl(read_pipe_ids[0], F_SETFL, O_NONBLOCK)==-1)
  220.     return(0);
  221.  
  222.   // Set the close on exec bits
  223.   if(fcntl(write_pipe_ids[1], F_SETFD, 1)==-1)
  224.     return(0);
  225.   if(fcntl(read_pipe_ids[0], F_SETFD, 1)==-1)
  226.     return(0);
  227.  
  228.   if((pid=fork()) == (pid_t)0)
  229.   {
  230.     // See if the pipes should be connected to STDIN and STDOUT
  231.     if(std_flag)
  232.     {
  233.       // Close STDIN and put the pipe in its place
  234.       if(dup2(write_pipe_ids[0],0)==-1)
  235.       close(write_pipe_ids[0]);
  236.  
  237.       // Close STDOUT and put the pipe in its place
  238.       if(dup2(read_pipe_ids[1],1)==-1)
  239.       close(read_pipe_ids[1]);
  240.  
  241.       // Dup the STDOUT to STDERR
  242.       dup2(1,2);
  243.     } 
  244.     else  
  245.     {
  246.       // If pipe isn't connected to STDIN and STDOUT then we will
  247.       // close STDIN, STDOUT, and STDERR and put the read pipe
  248.       // at descriptor 3 and the write pipe at descriptor 4.
  249.  
  250.       // First dup down to stdin and stdout
  251.       dup2(write_pipe_ids[0],0);
  252.       close(write_pipe_ids[0]);
  253.       dup2(read_pipe_ids[1],1);
  254.       close(read_pipe_ids[1]);
  255.  
  256.       // Now dup read pipe to 3 and write pipe to 4
  257.       dup2(0,3);
  258.       dup2(1,4);
  259.  
  260.       // Close STDIN, STDOUT, STDERR
  261.       close(0);
  262.       close(1);
  263.       close(2);
  264.     }
  265.  
  266.     String execCommand = "exec ";
  267.     execCommand += command;
  268.  
  269.     if(execl("/bin/sh","sh","-c",
  270.        (const char*)execCommand, NULL))
  271.       exit(0);
  272.   }
  273.   else
  274.   {
  275.     close(write_pipe_ids[0]);
  276.     close(read_pipe_ids[1]);
  277.     read_pipe_id=read_pipe_ids[0];
  278.     write_pipe_id=write_pipe_ids[1];
  279.     return(1);
  280.   }
  281. }
  282.  
  283.  
  284. M68681::~M68681()
  285. {
  286.   // We need to destory the Command Process
  287.   if(coma_pid != -1)
  288.   {
  289.     close(coma_read_id);
  290.     close(coma_write_id);
  291.     kill(coma_pid,SIGKILL);
  292.   }
  293.  
  294.   // We need to destory the Command Process
  295.   if(comb_pid != -1)
  296.   {
  297.     close(comb_read_id);
  298.     close(comb_write_id);
  299.     kill(comb_pid,SIGKILL);
  300.   }
  301. }
  302.  
  303. ///////////////////////////////////////////////////////////////////////////////
  304. // Perform a reset on the DUART 
  305. ///////////////////////////////////////////////////////////////////////////////
  306. void M68681::Reset()
  307. {
  308.   BasicDevice::Reset();              // Do the BasicDevice reset
  309.  
  310.   IVR = 0x0f;                        // 68000's Uninitialized interrupt vector
  311.   ISR = 0;                           // Clear the interrupt status register
  312.   IMR = 0;                           // Clear the interrupt mask register
  313.   SRA = 0;                           // Clear status register A
  314.   SRB = 0;                           // Clear status register B
  315.   receiver_a_state = INACTIVE;       // Set the channels to inactive state
  316.   transmitter_a_state = INACTIVE;
  317.   receiver_b_state = INACTIVE;
  318.   transmitter_b_state = INACTIVE;
  319.  
  320.   mr1a_pointer=1;                    // The mr?a address points to MR1A
  321.   mr1b_pointer=1;                    // The mr?b address points to MR1B
  322. }
  323.  
  324. ///////////////////////////////////////////////////////////////////////////////
  325. // Check to see if the address maps into this device
  326. ///////////////////////////////////////////////////////////////////////////////
  327. char M68681::CheckMapped(unsigned long addr)
  328. {
  329.   if((addr>=base_address) &&
  330.      (addr<=base_address+offset_to_first_register+15*offset_between_registers))
  331.   {
  332.     return(1);
  333.   }
  334.   else
  335.   {
  336.     return(0);
  337.   }
  338. }
  339.  
  340. ///////////////////////////////////////////////////////////////////////////////
  341. // Read one of the registers in the DUART
  342. ///////////////////////////////////////////////////////////////////////////////
  343. unsigned char M68681::Peek(unsigned long addr)
  344. {
  345.   addr -= (base_address+offset_to_first_register);
  346.  
  347.   if(addr==0)         // Mode Register A
  348.   {
  349.      if(mr1a_pointer)
  350.      {
  351.        mr1a_pointer=0;
  352.        return(MR1A);
  353.      }
  354.      else
  355.      {
  356.        return(MR2A);
  357.      }
  358.   }
  359.   else if(addr==1*offset_between_registers)    // Status Register A
  360.   {
  361.     return(SRA);
  362.   }
  363.   else if(addr==3*offset_between_registers)    // Receive Buffer A
  364.   {
  365.     SRA &= ~RxRDY;
  366.     SRA &= ~FFULL;
  367.     SetInterruptStatusRegister();
  368.     return(RBA);
  369.   }
  370.   else if(addr==5*offset_between_registers)    // Interrupt Status Register
  371.   {
  372.     return(ISR);
  373.   }
  374.   else if(addr==8*offset_between_registers)    // Mode Register B
  375.   {
  376.      if(mr1b_pointer)
  377.      {
  378.        mr1b_pointer=0;
  379.        return(MR1B);
  380.      }
  381.      else
  382.      {
  383.        return(MR2B);
  384.      }
  385.   }
  386.   else if(addr==9*offset_between_registers)    // Status Register B
  387.   {
  388.     return(SRB);
  389.   }
  390.   else if(addr==11*offset_between_registers)   // Receive Buffer B
  391.   {
  392.     SRB &= ~RxRDY;
  393.     SRB &= ~FFULL;
  394.     SetInterruptStatusRegister();
  395.     return(RBB);
  396.   }
  397.   else if(addr==12*offset_between_registers)   // Interrupt-vector register
  398.   {
  399.     return(IVR);
  400.   }
  401.   else
  402.     return(0);
  403. }
  404.  
  405. ///////////////////////////////////////////////////////////////////////////////
  406. // Write to one of the registers in the DUART
  407. ///////////////////////////////////////////////////////////////////////////////
  408. void M68681::Poke(unsigned long addr, unsigned char c)
  409. {
  410.   addr -= (base_address+offset_to_first_register);
  411.  
  412.   if(addr==0)         // Mode Register A
  413.   {
  414.      if(mr1a_pointer)
  415.      {
  416.        mr1a_pointer=0;
  417.        MR1A=c;
  418.        SetInterruptStatusRegister();
  419.      }
  420.      else
  421.      {
  422.        MR2A=c;
  423.      }
  424.   }
  425.   else if(addr==offset_between_registers)    // Clock-select Register A
  426.   {
  427.     CSRA=c;
  428.   }
  429.   else if(addr==2*offset_between_registers)    // Command Register A
  430.   {
  431.     switch ((c & 0x70) >> 4)
  432.     {
  433.       case 1:    // Reset mode register pointer
  434.         mr1a_pointer=1;
  435.         break;
  436.       case 2:    // Reset receiver
  437.         receiver_a_state=INACTIVE;
  438.         SRA &= ~RxRDY;
  439.         SRA &= ~FFULL;
  440.         SetInterruptStatusRegister();
  441.         break;
  442.       case 3:    // Reset transmitter
  443.         transmitter_a_state=INACTIVE;
  444.         SRA &= ~TxRDY;
  445.         SRA &= ~TxEMT;
  446.         SetInterruptStatusRegister();
  447.         break;
  448.       case 4:    // Clear error status
  449.         SRA &= 0x0f;
  450.         break;
  451.     }
  452.     switch ((c & 0x0c) >> 2)
  453.     {
  454.       case 1:    // Enable transmitter
  455.         transmitter_a_state=ACTIVE;
  456.         SRA |= TxRDY;
  457.         SRA |= TxEMT;
  458.         SetInterruptStatusRegister();
  459.         break;
  460.       case 2:    // Disable transmitter
  461.         transmitter_a_state=INACTIVE;
  462.         SRA &= ~TxRDY;
  463.         SRA &= ~TxEMT;
  464.         SetInterruptStatusRegister();
  465.         break;
  466.     }
  467.     switch (c & 0x3)
  468.     {
  469.       case 1:    // Enable receiver
  470.         receiver_a_state=ACTIVE;
  471.         SRA &= ~RxRDY;
  472.         SRA &= ~FFULL;
  473.         SetInterruptStatusRegister();
  474.         break;
  475.       case 2:
  476.         receiver_a_state=INACTIVE;
  477.         break;
  478.     }
  479.   }
  480.   else if (addr==3*offset_between_registers)   // Transmitter Buffer A
  481.   {
  482.     TBA=c;           // Store the transmit data
  483.     SRA &= ~TxRDY;   // Mark register as full
  484.     SRA &= ~TxEMT;
  485.     SetInterruptStatusRegister();
  486.  
  487.     if(ACR & 128)
  488.       cpu->events.Add(this, WRITE_A_CALLBACK,
  489.           (void*)0, baudrate_table[(CSRA & 0xf)+16]);
  490.     else
  491.       cpu->events.Add(this, WRITE_A_CALLBACK,
  492.           (void*)0, baudrate_table[(CSRA & 0xf)]);
  493.   }
  494.   else if(addr==5*offset_between_registers)    // Interrupt Mask Register
  495.   {
  496.     IMR=c;
  497.   }
  498.   else if(addr==8*offset_between_registers)    // Mode Register B
  499.   {
  500.      if(mr1b_pointer)
  501.      {
  502.        mr1b_pointer=0;
  503.        MR1B=c;
  504.        SetInterruptStatusRegister();
  505.      }
  506.      else
  507.      {
  508.        MR2B=c;
  509.      }
  510.   }
  511.   else if(addr==9*offset_between_registers)    // Clock-select Register B
  512.   {
  513.     CSRB=c;
  514.   }
  515.   else if(addr==10*offset_between_registers)   // Command Register B
  516.   {
  517.     switch ((c & 0x70) >> 4)
  518.     {
  519.       case 1:    // Reset mode register pointer
  520.         mr1b_pointer=1;
  521.         break;
  522.       case 2:    // Reset receiver
  523.         receiver_b_state=INACTIVE;
  524.         SRB &= ~RxRDY;
  525.         SRB &= ~FFULL;
  526.         SetInterruptStatusRegister();
  527.         break;
  528.       case 3:    // Reset transmitter
  529.         transmitter_b_state=INACTIVE;
  530.         SRB &= ~TxRDY;
  531.         SRB &= ~TxEMT;
  532.         SetInterruptStatusRegister();
  533.         break;
  534.       case 4:    // Clear error status
  535.         SRB &= 0x0f;
  536.         break;
  537.     }
  538.     switch ((c & 0x0c) >> 2)
  539.     {
  540.       case 1:    // Enable transmitter
  541.         transmitter_b_state=ACTIVE;
  542.         SRB |= TxRDY;
  543.         SRB |= TxEMT;
  544.         SetInterruptStatusRegister();
  545.         break;
  546.       case 2:    // Disable transmitter
  547.         transmitter_b_state=INACTIVE;
  548.         SRB &= ~TxRDY;
  549.         SRB &= ~TxEMT;
  550.         SetInterruptStatusRegister();
  551.         break;
  552.     }
  553.     switch (c & 0x3)
  554.     {
  555.       case 1:    // Enable receiver
  556.         receiver_b_state=ACTIVE;
  557.         SRB &= ~RxRDY;
  558.         SRB &= ~FFULL;
  559.         SetInterruptStatusRegister();
  560.         break;
  561.       case 2:
  562.         receiver_b_state=INACTIVE;
  563.         break;
  564.     }
  565.   }
  566.   else if(addr==11*offset_between_registers)   // Transmitter Buffer B
  567.   {
  568.     TBB=c;           // Store the transmit data
  569.     SRB &= ~TxRDY;   // Mark register as full
  570.     SRB &= ~TxEMT;
  571.     SetInterruptStatusRegister();
  572.  
  573.     if(ACR & 128)
  574.       cpu->events.Add(this, WRITE_B_CALLBACK,
  575.           (void*)0, baudrate_table[(CSRB & 0xf)+16]);
  576.     else
  577.       cpu->events.Add(this, WRITE_B_CALLBACK,
  578.           (void*)0, baudrate_table[(CSRB & 0xf)]);
  579.   }
  580.   else if(addr==12*offset_between_registers)   // Interrupt-vector register
  581.   {
  582.     IVR=c;
  583.   }
  584. }
  585.  
  586.  
  587. ///////////////////////////////////////////////////////////////////////////////
  588. // Handle event callbacks
  589. ///////////////////////////////////////////////////////////////////////////////
  590. void M68681::EventCallback(long type, void* pointer)
  591. {
  592.   SetInterruptStatusRegister();
  593.  
  594.   if(type==WRITE_A_CALLBACK)
  595.   {
  596.     unsigned char c;
  597.  
  598.     // If pipe is not availiable then just pretend we sent it somewhere
  599.     if(coma_write_id == -1)
  600.     {
  601.       SRA |= TxRDY;      // Ready for more data
  602.       SRA |= TxEMT;      // Transmitter is empty
  603.       SetInterruptStatusRegister();
  604.       return;
  605.     }
  606.     else if(transmitter_a_state==INACTIVE)
  607.     {
  608.       return;
  609.     }
  610.  
  611.     // Mask off bits that shouldn't be transmitted
  612.     switch (MR1A & 3)
  613.     {
  614.       case 0:
  615.         c=TBA & 0x1f;
  616.         break;
  617.       case 1:
  618.         c=TBA & 0x3f;
  619.         break;
  620.       case 2:
  621.         c=TBA & 0x7f;
  622.         break;
  623.  
  624.       default:
  625.         c=TBA;
  626.     }
  627.  
  628.     // Do the data transfer
  629.     switch ((MR2A & 0xc0) >> 6)
  630.     {
  631.       case 1:    // Automatic-echo mode (transmitter link disabled)
  632.         SRA |= TxRDY;
  633.         SRA |= TxEMT;
  634.         break;
  635.  
  636.       default:   // Normal mode
  637.         write(coma_write_id, &c ,1);
  638.         SRA |= TxRDY;      // Ready for more data
  639.         SRA |= TxEMT;      // Transmitter is empty
  640.         SetInterruptStatusRegister();
  641.     }        
  642.   }
  643.   else if(type==READ_A_CALLBACK)
  644.   {
  645.     unsigned char c;
  646.  
  647.     // If receiver is disabled or full then just add event and return
  648.     if((receiver_a_state==INACTIVE) || (SRA & FFULL))
  649.     {
  650.       // Reschedule another read callback to check for more characters
  651.       cpu->events.Add(this, READ_A_CALLBACK, 
  652.           (void*)0, DEFAULT_READ_CALLBACK_DURATION);
  653.       return;
  654.     }
  655.  
  656.     // Try to read a byte from the pipe
  657.     if(read(coma_read_id, &c, 1)==1)
  658.     {
  659.       // Mask off bits that shouldn't be received
  660.       switch (MR1A & 3)
  661.       {
  662.         case 0:
  663.           RBA=c & 0x1f;
  664.           break;
  665.         case 1:
  666.           RBA=c & 0x3f;
  667.           break;
  668.         case 2:
  669.           RBA=c & 0x7f;
  670.           break;
  671.  
  672.         default:
  673.           RBA=c;
  674.       }
  675.  
  676.       // Handle any special stuff for the funky modes
  677.       switch ((MR2A & 0xc0) >> 6)
  678.       {
  679.         case 1:    // Automatic-echo mode
  680.           write(coma_write_id, &RBA, 1);
  681.           break;
  682.       }        
  683.  
  684.       // If we're already full then set the overrun error bit
  685. //      if(SRA & FFULL)
  686. //        SRA |= 16;
  687.  
  688.       SRA |= RxRDY;
  689.       SRA |= FFULL;
  690.       SetInterruptStatusRegister();
  691.  
  692.       // Reschedule another read callback to check for more characters
  693.       if(ACR & 128)
  694.         cpu->events.Add(this, READ_A_CALLBACK,
  695.             (void*)0, baudrate_table[(CSRA >> 4)+16]);
  696.       else
  697.         cpu->events.Add(this, READ_A_CALLBACK,
  698.             (void*)0, baudrate_table[(CSRA >> 4)]);
  699.     }
  700.     else
  701.     {
  702.       // Reschedule another read callback to check for more characters
  703.       cpu->events.Add(this, READ_A_CALLBACK, 
  704.           (void*)0, DEFAULT_READ_CALLBACK_DURATION);
  705.     }
  706.   }
  707.   else if(type==WRITE_B_CALLBACK)
  708.   {
  709.     unsigned char c;
  710.  
  711.     // If pipe is not availiable then just pertend we sent it somewhere
  712.     if(comb_write_id == -1)
  713.     {
  714.       SRB |= TxRDY;
  715.       SRB |= TxEMT;
  716.       SetInterruptStatusRegister();
  717.       return;
  718.     }
  719.     else if(transmitter_b_state==INACTIVE)
  720.     {
  721.       return;
  722.     }
  723.  
  724.     // Mask off bits that shouldn't be transmitted
  725.     switch (MR1B & 3)
  726.     {
  727.       case 0:
  728.         c=TBB & 0x1f;
  729.         break;
  730.       case 1:
  731.         c=TBB & 0x3f;
  732.         break;
  733.       case 2:
  734.         c=TBB & 0x7f;
  735.         break;
  736.  
  737.       default:
  738.         c=TBB;
  739.     }
  740.  
  741.     // Do the data transfer
  742.     switch ((MR2B & 0xc0) >> 6)
  743.     {
  744.       case 1:    // Automatic-echo mode (transmitter link disabled)
  745.         SRB |= TxRDY;
  746.         SRB |= TxEMT;
  747.         break;
  748.       case 2:    // Local-loopback mode (not implemented) 
  749.       case 3:    // Multidrop mode (not implemented)
  750.  
  751.       default:   // Normal mode
  752.         write(comb_write_id, &c ,1);
  753.         SRB |= TxRDY;
  754.         SRB |= TxEMT;
  755.         SetInterruptStatusRegister();
  756.     }        
  757.   }
  758.   else if(type==READ_B_CALLBACK)
  759.   {
  760.     unsigned char c;
  761.  
  762.     // If receiver is disabled or full then just add event and return 
  763.     if((receiver_b_state==INACTIVE) || (SRB & FFULL))
  764.     {
  765.       if(SRB & FFULL)
  766.       {
  767.         if(ACR & 128)
  768.           cpu->events.Add(this, READ_B_CALLBACK,
  769.               (void*)0, baudrate_table[(CSRB >> 4)+16]);
  770.         else
  771.           cpu->events.Add(this, READ_B_CALLBACK,
  772.               (void*)0, baudrate_table[(CSRB >> 4)]);
  773.       }
  774.       else
  775.       {
  776.         // Reschedule another read callback to check for more characters
  777.         cpu->events.Add(this, READ_B_CALLBACK, 
  778.             (void*)0, DEFAULT_READ_CALLBACK_DURATION);
  779.       }
  780.       return;
  781.     }
  782.  
  783.     // Try to read a byte from the pipe
  784.     if(read(comb_read_id, &c, 1)==1)
  785.     {
  786.       // Mask off bits that shouldn't be received
  787.       switch (MR1B & 3)
  788.       {
  789.         case 0:
  790.           RBB=c & 0x1f;
  791.           break;
  792.         case 1:
  793.           RBB=c & 0x3f;
  794.           break;
  795.         case 2:
  796.           RBB=c & 0x7f;
  797.           break;
  798.  
  799.         default:
  800.           RBB=c;
  801.       }
  802.  
  803.       // Handle any special stuff for the funky modes
  804.       switch ((MR2B & 0xc0) >> 6)
  805.       {
  806.         case 1:    // Automatic-echo mode (transmitter link disabled)
  807.           write(comb_write_id, &RBB, 1);
  808.           break;
  809.       }        
  810.  
  811.       // If we're already full then set the overrun error bit
  812. //      if(SRB & FFULL)
  813. //        SRB |= 16;
  814.  
  815.       SRB |= RxRDY;
  816.       SRB |= FFULL;
  817.       SetInterruptStatusRegister();
  818.  
  819.       // Reschedule another read callback to check for more characters
  820.       if(ACR & 128)
  821.         cpu->events.Add(this, READ_B_CALLBACK,
  822.             (void*)0, baudrate_table[(CSRB >> 4)+16]);
  823.       else
  824.         cpu->events.Add(this, READ_B_CALLBACK,
  825.             (void*)0, baudrate_table[(CSRB >> 4)]);
  826.     }
  827.     else
  828.     {
  829.       // Reschedule another read callback to check for more characters
  830.       cpu->events.Add(this, READ_B_CALLBACK, 
  831.           (void*)0, DEFAULT_READ_CALLBACK_DURATION);
  832.     }
  833.   }
  834. }
  835.  
  836. ///////////////////////////////////////////////////////////////////////////////
  837. // Set the Interrupt Status Register (ISR) and request an interrupt if needed
  838. ///////////////////////////////////////////////////////////////////////////////
  839. void M68681::SetInterruptStatusRegister()
  840. {
  841.   ISR = 0;
  842.  
  843.   // See if transmitter A is ready for data
  844.   if(SRA & TxRDY)
  845.     ISR |= 1;
  846.  
  847.   // See if receiver A has data or if the FIFO is full
  848.   if(MR1A & 64)
  849.   {
  850.     if(SRA & FFULL)
  851.       ISR |= 2;
  852.   }
  853.   else
  854.   {
  855.     if(SRA & RxRDY)
  856.       ISR |= 2;
  857.   }
  858.  
  859.   // See if transmitter B is ready for data
  860.   if(SRB & TxRDY)
  861.     ISR |= 16;
  862.  
  863.   // See if receiver B has data or if the FIFO is full
  864.   if(MR1B & 64)
  865.   {
  866.     if(SRB & FFULL)
  867.       ISR |= 32;
  868.   }
  869.   else
  870.   {
  871.     if(SRB & RxRDY)
  872.       ISR |= 32;
  873.   }
  874.  
  875.   // Request an interrupt if one is needed
  876.   if(ISR & IMR)
  877.     InterruptRequest(interrupt_level);
  878. }
  879.  
  880. ///////////////////////////////////////////////////////////////////////////////
  881. // Acknowledege Interrupt - Called by CPU when it processes the interrupt
  882. ///////////////////////////////////////////////////////////////////////////////
  883. long M68681::InterruptAcknowledge(int level)
  884. {
  885.   if(interrupt_pending)
  886.   {
  887.     interrupt_pending=0;                 // Clear the pending interrupt flag
  888.     return(IVR);                         // Return the programmed Interrupt Vector 
  889.   }
  890.   else
  891.   {
  892.     return(SPURIOUS_INTERRUPT);
  893.   }
  894. }
  895.  
  896.